package com.sugon.modules.device.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.dao.DevAmPlanItemDao;
import com.sugon.dao.DevMaintenPlanDao;
import com.sugon.dao.DevPlanOptionDao;
import com.sugon.dao.DevPlanRuleDao;
import com.sugon.entity.DevAmRulesOptionEntity;
import com.sugon.entity.DevMaintenPlanEntity;
import com.sugon.entity.DevPlanOptionEntity;
import com.sugon.entity.SysMsgEntity;
import com.sugon.modules.base.consts.SysApproveStatusConst;
import com.sugon.modules.base.model.vo.BaseApproveParamVO;
import com.sugon.modules.base.model.vo.ProcessProgressConst;
import com.sugon.modules.device.model.entity.DevMaintenancePlanEntity;
import com.sugon.modules.device.service.IDeviceMaintenancePlanManager;
import com.sugon.modules.device.service.IDeviceMaintenanceRuleManager;
import com.sugon.modules.sys.consts.ProcessApproveStatus;
import com.sugon.modules.sys.consts.ProcessProgressStatus;
import com.sugon.service.*;
import com.sugon.utils.ProcessInfoEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ： YuXD
 * @description：
 * @date ： 2020-10-12 下午 3:44
 * @version: 1.0
 */
@Service
public class DeviceMaintenanceRuleManagerImpl implements IDeviceMaintenanceRuleManager {

    @Resource
    private DevPlanOptionDao devPmRuleOptionDao;
    @Autowired
    private SysMsgService msgService;
    @Autowired
    private SysProcessInfoService processInfoService;
    @Autowired
    private DevMaintenPlanDao devMaintenPlanDao;
    @Resource
    private DevMaintenPlanService devPmRuleService;
    @Resource
    private DevPmRuleItemService devPlanOptionService;
    @Resource
    private DevAmRulesOptionService devAmRulesOptionService;
    @Resource
    private DevPlanRuleDao devPlanRuleDao;
    @Resource
    private DevAmPlanItemDao devAmPlanItemDao;
    @Resource
    private DevPmRuleItemService devPmRuleItemService;
    @Resource
    private IDeviceMaintenancePlanManager devPmPlanManager;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public DevMaintenPlanEntity deleteMaintenanceRuleOption(String id) {
        /*
            删除维护项时有两种情况：已审核通过的 、 其它
            如果是审核通过的，那么需要克隆生成新的设备维护规程
            如果是其它，则可以直接删除
         */
        DevPlanOptionEntity devPlanOption = devPlanOptionService.queryObject(id);
        cn.hutool.core.lang.Assert.notNull(devPlanOption);
        DevMaintenPlanEntity devPmRule = devPmRuleService.queryObject(devPlanOption.getPlanId());
        Assert.notNull(devPmRule, "维护规程[" + devPlanOption.getPlanId() + "]不存在，请联系管理员！");
        if (NumberUtil.equals(ProcessProgressConst.PASSED, devPmRule.getProgress())) {
            // 克隆时需要排除的维护项ID
            List<String> excludePmItemList = CollectionUtil.newArrayList(devPlanOption.getMainBaseId());
            devPmRule = cloneDevPmRule(devPlanOption.getPlanId(), excludePmItemList, null);
        } else {
            int deleteFlag = devPlanOptionService.delete(id);
            cn.hutool.core.lang.Assert.isTrue(deleteFlag > 0);
        }
        return devPmRule;
    }

    /**
     * 对已有的设备维护规程进行克隆，排除掉需要排除的，添加需要新增的
     *
     * @param originalPmRuleId  原设备维护规程iD
     * @param excludePmItemList 需要排除的设备维护项
     * @param addPmItemList     需要添加的设备维护项
     * @return
     */
    @Override
    public DevMaintenPlanEntity cloneDevPmRule(String originalPmRuleId, List<String> excludePmItemList, List<String> addPmItemList) {
        DevMaintenPlanEntity devPmRule = devPmRuleService.queryObject(originalPmRuleId);
        Assert.notNull(devPmRule, "维护规程[" + originalPmRuleId + "]不存在，请联系管理员！");
        // 获取原维护项列表
        List<DevPlanOptionEntity> originalPmOptionList = devPmRuleItemService.getByPlanId(originalPmRuleId);
        /*
            理论上一个设备 处于新建状态的只有一个
            1、每次克隆时首先去判断当前设备是否有一个新建的设备维护规程
            如果有则沿用，没有则新建
            2、从需要克隆的设备维护规程项中排除需要排除的，添加需要新增的
            3、保存关联关系
         */
        List<DevMaintenPlanEntity> existedNewPmRuleList = devPmRuleService.list(devPmRule.getDevId(), ProcessProgressConst.DEPT_APPROVING, 1);
        if (CollectionUtil.isNotEmpty(existedNewPmRuleList)) {
            // 检测下处于新增状态的该设备维护规程是否沿用的是一个规程
            devPmRule = existedNewPmRuleList.get(0);
            if (StrUtil.isEmpty(devPmRule.getPreRuleId()) || !devPmRule.getPreRuleId().equals(originalPmRuleId)) {
                devPmRule.setPreRuleId(originalPmRuleId);
                devPmRuleService.update(devPmRule);
            }
            // 获取存在的设备维护项列表
            originalPmOptionList = devPmRuleItemService.getByPlanId(devPmRule.getId());
            // 清空下既存的，防止重复
            devPmRuleOptionDao.clearAllByRuleId(devPmRule.getId());
        } else {
            devPmRule.setPreRuleId(devPmRule.getId());
            devPmRule.setProgress(ProcessProgressConst.DEPT_APPROVING);
            devPmRule.setIsValid(1);
            devPmRuleService.save(devPmRule);
        }
        // 获取最新的设备维护项列表
        List<String> newlyDevPmRuleItemList = buildPmOptionList(originalPmOptionList, excludePmItemList, addPmItemList);
        // 保存设备维护项
        if (CollectionUtil.isNotEmpty(newlyDevPmRuleItemList)) {
            DevPlanOptionEntity devPlanOption;
            for (String newlyDevPmRuleItem : newlyDevPmRuleItemList) {
                devPlanOption = new DevPlanOptionEntity(devPmRule.getId(), newlyDevPmRuleItem);
                devPmRuleItemService.save(devPlanOption);
            }
        }
        return devPmRule;
    }

    /**
     * 构建最终的设备维护规程项列表
     * 逻辑：从devPmRuleId指定的规程维护项中排除掉excludePmItemList，新增addPmItemList
     * 同时去重
     *
     * @param originalPmOptionList 原始设备维护规程
     * @param excludePmItemList    需要排除的设备维护项ID列表
     * @param addPmItemList        需要添加的设备维护项ID列表
     * @return
     */
    private List<String> buildPmOptionList(List<DevPlanOptionEntity> originalPmOptionList, List<String> excludePmItemList, List<String> addPmItemList) {
        // 新建一个列表，将原有的规程项优先放置进去
        List<String> newlyDevPmRuleItemList = CollectionUtil.newArrayList();
        if (CollectionUtil.isNotEmpty(originalPmOptionList)) {
            newlyDevPmRuleItemList.addAll(originalPmOptionList.stream().map(DevPlanOptionEntity::getMainBaseId).collect(Collectors.toList()));
        }
        // 排除掉需要排除的
        if (CollectionUtil.isNotEmpty(excludePmItemList)) {
            newlyDevPmRuleItemList = newlyDevPmRuleItemList.stream().filter(devPmOptionId -> !excludePmItemList.contains(devPmOptionId)).collect(Collectors.toList());
        }
        // 添加需要添加的
        if (CollectionUtil.isNotEmpty(addPmItemList)) {
            newlyDevPmRuleItemList.addAll(addPmItemList);
            newlyDevPmRuleItemList = newlyDevPmRuleItemList.stream().distinct().collect(Collectors.toList());
        }
        return newlyDevPmRuleItemList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteAmRulesOption(String id) {
        /*
            当设备维护规程项变化时，
            如果当前规程已关联设备维护计划，那么
         */
        DevAmRulesOptionEntity amRulesOption = devAmRulesOptionService.queryObject(id);
        Assert.notNull(amRulesOption, "自主维护规程项不存在，ID：" + id);
        int deleteFlag = devAmRulesOptionService.delete(id);
        if (deleteFlag > 0) {
             /*
                如果要删除的规程已制定成维护计划，那么需要关联删除对应的设备维护计划项
             */
            List<DevMaintenancePlanEntity> maintenancePlanList = devPlanRuleDao.findMatched(amRulesOption.getPlanId());
            if (CollectionUtil.isNotEmpty(maintenancePlanList)) {
                List<String> planIdList = maintenancePlanList.stream().map(DevMaintenancePlanEntity::getId).collect(Collectors.toList());
                devAmPlanItemDao.deleteByPlanIdAndMainBaseId(planIdList, amRulesOption.getMainBaseId());
            }
        }
        return true;
    }

    /**
     * workshopBatchApprove
     *
     * @param approveParam
     * @return
     */
    @Override
    public boolean workshopBatchApprove(BaseApproveParamVO approveParam) {
        List<String> approveIdList = approveParam.getApproveIdList();
        int totalRows = 0;
        DevMaintenPlanEntity devMaintenRule;
        // 获取审核结果
        int approveStatus = approveParam.getStatus();

        for (String approveItemId : approveIdList) {
            devMaintenRule = devPmRuleService.queryObject(approveItemId);
            Assert.notNull(devMaintenRule, "维护规程信息不存在，请确认！");
            // 校验规程进度
            Assert.isTrue(devMaintenRule.getProgress().equals(ProcessProgressConst.DEPT_APPROVING), "只可以审核处于车间审核状态的规程信息");
            // 创建公共消息
            SysMsgEntity sysMsg = new SysMsgEntity();
            sysMsg.setDataId(approveItemId);
            sysMsg.setDataUrl("../device/devmaintenplan.html?Id=" + approveItemId);
            // 如果审核通过
            if (approveStatus == SysApproveStatusConst.PASSED) {
                devMaintenRule.setProgress(ProcessProgressConst.CJ_PE_APPROVING);
                int rows = devPmRuleService.update(devMaintenRule);
                if (rows > 0) {
                    totalRows += rows;
                    // 1、生成流程节点信息
                    processInfoService.saveProcessInfo(null, approveItemId, ProcessInfoEnum.DEV_WHGC, ProcessApproveStatus.PASSED_WITH_APPROVE, null, approveParam.getRemark(), ProcessProgressStatus.ING);
                    // 2、生成下一节点审核系统消息
                    msgService.addApproveItem(ProcessInfoEnum.DEV_WHGC, sysMsg, 1);
                }
            } else if (approveStatus == SysApproveStatusConst.NOT_PASSED) {
                devMaintenRule.setProgress(ProcessProgressConst.NOT_PASSED);
                int rows = devPmRuleService.update(devMaintenRule);
                if (rows > 0) {
                    totalRows += rows;
                    // 1、生成流程节点信息
                    processInfoService.saveProcessInfo(null, approveItemId, ProcessInfoEnum.DEV_WHGC, approveStatus, null, approveParam.getRemark(), ProcessProgressStatus.ING);
                    // 2、通知编制人维护规程未通过审核
                    sysMsg.setUserId(devMaintenRule.getOrgUserId());
                    sysMsg.setRemark(StrUtil.format(ProcessInfoEnum.DEV_WHGC.getNotPassedMsgTemplate(), devMaintenRule.getRuleName(), approveParam.getRemark()));
                    // 保存消息
                    msgService.addApproveItem(ProcessInfoEnum.DEV_WHGC, sysMsg, 0);
                }
            }
        }
        return totalRows == approveIdList.size();
    }

    /**
     * peBatchApprove
     *
     * @param approveParam
     * @return
     */
    @Override
    public boolean peBatchApprove(BaseApproveParamVO approveParam) {
        List<String> approveIdList = approveParam.getApproveIdList();
        int totalRows = 0;
        DevMaintenPlanEntity devMaintenRule;
        // 获取审核结果
        int approveStatus = approveParam.getStatus();

        for (String approveItemId : approveIdList) {
            devMaintenRule = devPmRuleService.queryObject(approveItemId);
            Assert.notNull(devMaintenRule, "维护规程信息不存在，请确认！");
            // 校验规程进度
            Assert.isTrue(devMaintenRule.getProgress().equals(ProcessProgressConst.CJ_PE_APPROVING), "只可以审核已通过车间审核的规程信息！");
            // 创建公共消息
            SysMsgEntity sysMsg = new SysMsgEntity();
            sysMsg.setDataId(approveItemId);
            sysMsg.setDataUrl("../device/devmaintenplan.html?Id=" + approveItemId);
            // 如果审核通过
            if (approveStatus == SysApproveStatusConst.PASSED) {
                devMaintenRule.setProgress(ProcessProgressConst.PASSED);
                int rows = devPmRuleService.update(devMaintenRule);
                if (rows > 0) {
                    totalRows += rows;
                    // 替换设备维护规程
                    if (StrUtil.isNotEmpty(devMaintenRule.getPreRuleId())) {
                        devPmPlanManager.changePmRule(devMaintenRule.getPreRuleId(), devMaintenRule.getId());
                    }
                    // 1、失效当前设备的早期版本
                    devMaintenPlanDao.invalid(devMaintenRule.getDevId(), approveItemId);
                    // 2、生成流程节点信息
                    processInfoService.saveProcessInfo(null, approveItemId, ProcessInfoEnum.DEV_WHGC, ProcessApproveStatus.PASSED_WITH_APPROVE, null, approveParam.getRemark(), ProcessProgressStatus.END);
                    // 3、删除所有消息
                    sysMsg.setRemark(StrUtil.format(ProcessInfoEnum.DEV_WHGC.getPassedMsgTemplate()));
                    sysMsg.setDataFlag(ProcessProgressStatus.END + "");
                    msgService.addApproveItem(ProcessInfoEnum.DEV_WHGC, sysMsg, 1);
                }
            } else if (approveStatus == SysApproveStatusConst.NOT_PASSED) {
                devMaintenRule.setProgress(ProcessProgressConst.NOT_PASSED);
                int rows = devPmRuleService.update(devMaintenRule);
                if (rows > 0) {
                    totalRows += rows;
                    // 1、生成流程节点信息
                    processInfoService.saveProcessInfo(null, approveItemId, ProcessInfoEnum.DEV_WHGC, approveStatus, null, approveParam.getRemark(), ProcessProgressStatus.ING);
                    // 2、通知编制人维护规程未通过审核
                    sysMsg.setUserId(devMaintenRule.getOrgUserId());
                    sysMsg.setRemark(StrUtil.format(ProcessInfoEnum.DEV_WHGC.getNotPassedMsgTemplate(), devMaintenRule.getRuleName(), approveParam.getRemark()));
                    msgService.addApproveItem(ProcessInfoEnum.DEV_WHGC, sysMsg, 0);
                }
            }
        }
        return totalRows == approveIdList.size();
    }

}
